package com.bzkj.document.service.purchase.impl;

import com.bzkj.common.annotation.DataWarehouseScope;
import com.bzkj.common.constant.BillStatusConstant;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.enums.BusinessType;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.purchaseinorder.dto.PurchaseInboundDTO;
import com.bzkj.document.domain.purchaseinorder.vo.PurchaseInboundBodyVO;
import com.bzkj.document.domain.purchaseinorder.vo.PurchaseInboundHeadVO;
import com.bzkj.document.mapper.PurchaseInStockMapper;
import com.bzkj.document.service.purchase.PurchaseInService;
import com.bzkj.document.service.purchase.PurchaseService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @projectName: bzkj-wms
 * @package: com.bzkj.document.service.purchase.impl
 * @className: PurchaseInServiceImpl
 * @description: 采购入库单服务层实现类
 * @author: C1309
 * @createDate: 2024年11月27日
 * @version: v1.0
 */
@Service
public class PurchaseInServiceImpl implements PurchaseInService {

    /**
     * NCC接口请求工具
     */
    @Resource
    private NccHttpUtils nccHttpUtils;

    /**
     * 采购入库持久层
     */
    @Resource
    private PurchaseInStockMapper purchaseInStockMapper;

    @Resource
    private PurchaseService purchaseService;

    /**
     * 消息工具
     */
    @Resource
    private MessageUtil messageUtil;

    /**
     * 签字完成后wms库存记录
     */
    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    /**
     * 固定的 pk_org 值
     */
    private static final String PK_ORG = "111";

    /**
     * NCC签字
     */
    private static final String SIGN_URL = "/nccloud/api/ic/purchasein/sign";

    /**
     * NCC更新采购入库单
     */
    private static final String PURCHASE_UPDATE_URL = "/nccloud/api/ic/purchasein/update";

    /**
     * NCC删除
     */
    private static final String DELETE_API_URL = "/nccloud/api/ic/purchasein/delete";


    /**
     * 获取采购入库单
     *
     * @param requestDTO 请求参数
     * @param pageNum    页码
     * @param pageSize   页面大小
     * @return 采购入库单
     */
    @Override
    @DataWarehouseScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo getPurchaseInOrder(PurchaseInboundDTO requestDTO, int pageNum, int pageSize) {
        // 处理日期范围过滤条件
        DataProcessUtils.handleDateRange(requestDTO);

        // 处理单据状态过滤条件
        String originalBillsState = Optional.ofNullable(requestDTO.getBillsState())
                .filter(state -> !state.isEmpty())
                .orElse(null);

        // For header query, we modify state 4/5 to 3
        String headerQueryBillsState = originalBillsState != null
                ? (originalBillsState.equals("4") || originalBillsState.equals("5") ? "3" : originalBillsState)
                : null;
        requestDTO.setBillsState(headerQueryBillsState);

        // 查询表头数据
        List<PurchaseInboundHeadVO> inboundHeadVOList = purchaseInStockMapper.selectPurchaseInStockHeader(requestDTO);
        if (inboundHeadVOList.isEmpty()) {
            return DataProcessCommonUtils.getTableInfo(Collections.emptyList(), pageNum, pageSize);
        }

        // 获取物料过滤条件
        String filterMaterialOid = Optional.ofNullable(requestDTO.getMaterial()).orElse("");
        boolean shouldFilterByMaterial = !filterMaterialOid.isEmpty();
        boolean shouldFilterBySkuState = originalBillsState != null
                && (originalBillsState.equals("4") || originalBillsState.equals("5"));

        // 并行处理表头数据
        List<HashMap<String, Object>> responseDataList = inboundHeadVOList.parallelStream()
                .map(headVO -> {
                    // 查询对应单据明细
                    List<PurchaseInboundBodyVO> bodyList = purchaseInStockMapper.selectPurchaseInStockDetails(
                            headVO.getCgeneralhid(),
                            headVO.getBillsState()
                    );

                    if (bodyList == null || bodyList.isEmpty()) {
                        return null;
                    }

                    // 应用过滤条件
                    if (shouldFilterByMaterial && bodyList.stream()
                            .noneMatch(body -> filterMaterialOid.equals(body.getCmaterialoid().getPk()))) {
                        return null;
                    }

                    if (shouldFilterBySkuState && bodyList.stream()
                            .noneMatch(body -> originalBillsState.equals(body.getSkuState()))) {
                        return null;
                    }

                    // 构建结果
                    HashMap<String, Object> result = new HashMap<>(2);
                    result.put("header", headVO);
                    result.put("details", bodyList);
                    return result;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        return DataProcessCommonUtils.getTableInfo(responseDataList, pageNum, pageSize);
    }


    // ==========================================================
    // 模块名称: 采购入库单删除模块
    // 功能描述: 根据不同的消息模式返回不同的提示信息
    // ==========================================================

    /**
     * 删除采购入库单
     *
     * @param cgeneralhid 表头主键
     * @param loginUser   登录用户
     * @return 结果
     */
    @Override
    public AjaxResult deletePurchaseInboundOrder(String cgeneralhid, LoginUser loginUser, String reason) {

        if (cgeneralhid == null) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.PURCHASE_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } else if (cgeneralhid.trim().isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.PURCHASE_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        }

        // 获取当前单据状态
        Map<String, String> billStateMap = purchaseInStockMapper.getBillStatus(cgeneralhid);
        String billStatus = billStateMap.get("billState");
        String billCode = billStateMap.get("vbillcode");

        // 调用消息工具（根据不同的单据状态返回不同的消息）
        AjaxResult ajaxResult = messageUtil.deleteBillMessage(billStatus, DocumentType.PURCHASE_INBOUND.getDescription());

        return ajaxResult.isSuccess() ? handleDeleteBill(cgeneralhid, billCode, loginUser, reason) : ajaxResult;

    }

    /**
     * 采购入库单删除
     *
     * @param cgeneralhid 表头主键
     * @param billCode    单据编号
     * @param loginUser   登录用户
     * @param reason      删除原因
     * @return 结果
     */
    private AjaxResult handleDeleteBill(String cgeneralhid, String billCode, LoginUser loginUser, String reason) {
        try {
            // 调用删除接口
            NccApiResponse nccApiResponse = nccHttpUtils.post(DELETE_API_URL, "[" + cgeneralhid + "]");

            // 校验NCC响应
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            purchaseInStockMapper.updateBillState(cgeneralhid, BillStatusConstant.DELETED_CODE, loginUser.getUsername(), reason);
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(billCode), DocumentType.PURCHASE_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } catch (Exception e) {
            //log.error("采购入库单修改异常: ", e);
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.PURCHASE_INBOUND.getCode(), e, BusinessType.INVALID.getDescription());
            throw new RuntimeException(errorMessage, e);
        }
    }

    // ==========================================================
    // 模块名称: 采购入库单签字模块
    // 功能描述: 对NCC采购入库单进行签字操作
    // ==========================================================

    /**
     * 采购入库单签字
     *
     * @param cgeneralhid 表头主键
     * @param loginUser   登录用户
     * @return 结果
     */
    @Override
    public AjaxResult auditPurchaseInboundOrder(String cgeneralhid, LoginUser loginUser) {
        if (cgeneralhid == null) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.PURCHASE_INBOUND.getCode(), BusinessType.SIGN.getDescription()));
        } else if (cgeneralhid.isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.PURCHASE_INBOUND.getCode(), BusinessType.SIGN.getDescription()));
        }

        // 获取当前单据状态
        Map<String, String> billStateMap = purchaseInStockMapper.getBillStatus(cgeneralhid);
        String billStatus = billStateMap.get("billState");
        String billCode = billStateMap.get("vbillcode");
        // 根据单据状态返回消息
        AjaxResult ajaxResult = messageUtil.signedBillMessage(billStatus, DocumentType.PURCHASE_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? processSignBill(cgeneralhid, billCode, loginUser) : ajaxResult;
    }

    /**
     * 对已完成的单据进行签字处理
     *
     * @param cgeneralhid 表头主键
     * @param vBillCode   单据编号
     * @param loginUser   登录用户
     * @return 结果
     */
    private AjaxResult processSignBill(String cgeneralhid, String vBillCode, LoginUser loginUser) {
        try {
            // 准备表头数据
            HashMap<String, Object> headerMap = prepareHeaderData(cgeneralhid);
            String vtrantypecode = headerMap.get("vtrantypecode").toString();

            // 校验并准备明细数据
            List<HashMap<String, Object>> detailList = prepareDetails(cgeneralhid, vtrantypecode);
            if (detailList.isEmpty()) {
                return AjaxResult.error(messageUtil.updateDocumentZeroQuantityMessage(DocumentType.PURCHASE_INBOUND.getCode()));
            }

            // 更新采购单
            AjaxResult updateResult = updatePurchaseOrder(headerMap, detailList, loginUser);
            if (!updateResult.isSuccess()) {
                return updateResult;
            }

            // 调用外部接口并更新状态
            return handleExternalApiAndInventory(cgeneralhid, vBillCode, loginUser, detailList.size());
        } catch (Exception e) {
//            logError("采购入库单签字异常", e); // 记录异常日志
            e.printStackTrace();
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.PURCHASE_INBOUND.getCode(), e, BusinessType.SIGN.getDescription());
            throw new RuntimeException(exceptionMessage, e);
        }
    }

    /**
     * 校验并准备明细数据
     *
     * @param cgeneralhid 单据表头主键
     * @return 明细列表或null（校验失败）
     */
    private List<HashMap<String, Object>> prepareDetails(String cgeneralhid, String vtrantypecode) {
        // 查询单据明细信息
        List<PurchaseInboundBodyVO> details = purchaseInStockMapper.selectPurchaseInStockDetails(cgeneralhid, null);
        // 构建更新明细列表
        List<HashMap<String, Object>> detailList = new ArrayList<>();
        // 校验库存是否充足
        boolean verifyInventory = inventoryManagerUtils.verifyInventorySign(details, "warehousein", vtrantypecode, DocumentType.PURCHASE_INBOUND.getCode());
        if (verifyInventory) {
            details.forEach(detail -> {
                HashMap<String, Object> detailMap = new HashMap<>();
                detailMap.put("cgeneralbid", detail.getCgeneralbid());
                detailMap.put("nnum", detail.getNnum());
                detailList.add(detailMap);
            });
        }
        return detailList;
    }

    /**
     * 准备表头数据
     *
     * @param cgeneralhid 表头主键
     * @return 表头数据
     */
    private HashMap<String, Object> prepareHeaderData(String cgeneralhid) {
        PurchaseInboundHeadVO inboundHeader = purchaseInStockMapper.selectPurchaseInHeaderByBillCode(cgeneralhid);
        if (inboundHeader == null) {
            throw new IllegalStateException("采购入库单表头信息不存在！");
        }

        HashMap<String, Object> headerMap = new HashMap<>();
        headerMap.put("cgeneralhid", inboundHeader.getCgeneralhid());
        headerMap.put("vtrantypecode", inboundHeader.getVtrantypecode());
        return headerMap;
    }

    /**
     * 更新采购单
     *
     * @param headerMap  表头数据
     * @param detailList 明细列表
     * @param loginUser  登录用户
     * @return 更新结果
     */
    private AjaxResult updatePurchaseOrder(HashMap<String, Object> headerMap, List<HashMap<String, Object>> detailList, LoginUser loginUser) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("header", headerMap);
        resultMap.put("details", detailList);

        return purchaseService.updatePurchase(resultMap, loginUser, true);
    }

    /**
     * 处理外部接口调用和库存更新
     *
     * @param cgeneralhid 表头主键
     * @param vBillCode   单据编号
     * @param loginUser   登录用户
     * @param detailSize  明细数量
     * @return 结果
     */
    private AjaxResult handleExternalApiAndInventory(String cgeneralhid, String vBillCode, LoginUser loginUser, int detailSize) throws IOException {
        // 调用外部接口
        NccApiResponse apiResponse = nccHttpUtils.post(SIGN_URL, "[" + cgeneralhid + "]");

        DataProcessCommonUtils.validateNccResponse(apiResponse);

        // 更新单据状态
        purchaseInStockMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), null);

        // 更新库存管理
        Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(vBillCode, "PurchaseWareHouseIn");
        if (rowCount != null && detailSize == rowCount) {
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vBillCode), DocumentType.PURCHASE_INBOUND.getCode(), BusinessType.SIGN.getDescription()));
        } else {
            purchaseInStockMapper.updateBillState(cgeneralhid, BillStatusConstant.WMS_FAILURE_CODE, loginUser.getUsername(), null);
            return AjaxResult.error(messageUtil.updateDocumentWmsFailureMessage(DocumentType.PURCHASE_INBOUND.getCode()));
        }
    }
}
